package com.wolfsea.launcherdemo
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.ViewGroup
import androidx.core.view.get

/**
 *@desc  RootContentLayout
 *@author liuliheng
 *@time 2022/12/20  10:31
 **/
class RootContentLayout @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null
) : ViewGroup(context, attributeSet) {

    private val hotSetItemSpace = context.resources.getDimension(R.dimen.dp_45).toInt()

    private var downX = 0
    private var downY = 0
    private var flagDownX = 0
    private var flagDownY = 0

    private var totalMovedXDistance = 0
    //lastTotalMovedXDistance确保移动的距离为width的整数倍
    private var lastTotalMovedXDistance = 0
    private var calcMovedXDistance = 0

    private var totalMovedYDistance = 0
    //lastTotalMovedXDistance确保移动的距离为height的整数倍
    private var lastTotalMovedYDistance = 0
    private var calcMovedYDistance = 0

    private var topLayoutMovedX = 0
    private var topLayoutMovedY = 0

    private var currentChildIndex = 1

    private var showedContentType = SHOW_SLIDE_CONTENT

    private var topContentLayoutShowed = false
    private var bottomContentLayoutShowed = false

    private var launcherLayout: LauncherLayout2? = null
    private var bottomContentLayout: BottomContentLayout? = null
    private var slideContentLayout: SlideContentLayout? = null
    private var topContentLayout: TopContentLayout? = null

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        for (i in 0.until(childCount)) {
            val child = get(i)
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0)
        }
        setMeasuredDimension(
            MeasureSpec.getSize(widthMeasureSpec) - paddingStart - paddingRight,
            MeasureSpec.getSize(heightMeasureSpec) - paddingTop - paddingBottom
        )
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        for (i in 0.until(childCount)) {
            val child = get(i)
            val measuredWidth = child.measuredWidth
            val measuredHeight = child.measuredHeight
            val layoutParams = child.layoutParams as MarginLayoutParams

            when (i) {
                childCount - 1 -> {
                    child.layout(
                        layoutParams.leftMargin + topLayoutMovedX,
                        layoutParams.topMargin - measuredHeight + topLayoutMovedY,
                        layoutParams.leftMargin + measuredWidth + topLayoutMovedX,
                        layoutParams.topMargin + topLayoutMovedY
                    )
                }
                childCount - 2 -> {
                    child.layout(
                        layoutParams.leftMargin,
                        measuredHeight + layoutParams.topMargin + totalMovedYDistance,
                        measuredWidth + layoutParams.leftMargin,
                        measuredHeight * 2 + layoutParams.topMargin + totalMovedYDistance
                    )
                }
                childCount - 3 -> {
                    child.layout(
                        layoutParams.leftMargin,
                        this.measuredHeight - measuredHeight - hotSetItemSpace,
                        measuredWidth + layoutParams.leftMargin,
                        this.measuredHeight - hotSetItemSpace
                    )
                }
                else -> {
                    child.layout(
                        measuredWidth * (i - 1) + layoutParams.leftMargin,
                        layoutParams.topMargin,
                        measuredWidth * i + layoutParams.leftMargin,
                        measuredHeight + layoutParams.topMargin
                    )
                }
            }
        }
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        when (ev?.action) {
            MotionEvent.ACTION_DOWN -> {
                flagDownX = ev.x.toInt()
                downX = flagDownX
                flagDownY = ev.y.toInt()
                downY = flagDownY
            }
            MotionEvent.ACTION_MOVE -> {
                val moveX = ev.x.toInt()
                val moveY = ev.y.toInt()
                val diffValueX = moveX - downX
                val diffValueY = moveY - downY
                val condition = Math.abs(diffValueX) > Math.abs(diffValueY)

                if ((currentChildIndex == 0 || currentChildIndex == 1) && topContentLayoutShowed) {
                    return true
                }

                if ((currentChildIndex == 0 && condition/* && !launcherLayout?.itemInDragging()!!*/)
                    || (launcherLayout?.getCurrentPage() == 0 && diffValueX > 0
                            && condition /*&& !launcherLayout?.itemInDragging()!!*/)
                ) {
                    topLayoutMovedX = - measuredWidth

                    downX = moveX
                    downY = moveY
                    showedContentType = SHOW_SLIDE_CONTENT
                    Log.d(TAG, "showedContentType = SHOW_SLIDE_CONTENT")
                    return true
                }

                if (currentChildIndex == 1 && !condition
                    && -diffValueY >= BaseConstant.MIN_SLIDE_DISTANCE && !topContentLayoutShowed
                    /*&& !launcherLayout?.itemInDragging()!!*/
                ) {
                    topLayoutMovedX = 0

                    downX = moveX
                    downY = moveY
                    showedContentType = SHOW_BOTTOM_CONTENT
                    Log.d(TAG, "showedContentType = SHOW_SLIDE_CONTENT---currentChildIndex == 1")
                    return true
                }

                if (currentChildIndex == 2 && bottomContentLayout?.childResumeOriginState()!!
                    && diffValueY > 0
                ) {
                    topLayoutMovedX = 0

                    downX = moveX
                    downY = moveY
                    showedContentType = SHOW_BOTTOM_CONTENT
                    Log.d(TAG, "showedContentType = SHOW_SLIDE_CONTENT---SHOW_BOTTOM_CONTENT == 2")
                    return true
                }

                if (!bottomContentLayoutShowed && ((currentChildIndex != 0 && !condition && Math.abs(diffValueY) > BaseConstant.MIN_SLIDE_DISTANCE)
                    || (currentChildIndex == 0 && diffValueY > 0 && slideContentLayout?.inOriginState()!!)
                    || (topContentLayoutShowed && currentChildIndex == 0))) {
                    downX = moveX
                    downY = moveY
                    showedContentType = SHOW_TOP_CONTENT
                    Log.d(TAG, "showedContentType = SHOW_TOP_CONTENT---SHOW_TOP_CONTENT == 3")
                    return true
                }
            }
        }
        return super.onInterceptTouchEvent(ev)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        performClick()
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {
                flagDownX = event.x.toInt()
                downX = flagDownX
                flagDownY = event.y.toInt()
                downY = flagDownY
            }
            MotionEvent.ACTION_MOVE -> {
                Log.d(TAG, "onTouchEvent-->ACTION_MOVE")
                when (showedContentType) {
                    SHOW_SLIDE_CONTENT -> {
                        actionMoveShowSlideContent(event)
                    }
                    SHOW_BOTTOM_CONTENT -> {
                        actionMoveShowBottomContent(event)
                    }
                    SHOW_TOP_CONTENT -> {}
                    else -> {}
                }
            }
            MotionEvent.ACTION_UP -> {
                Log.d(TAG, "onTouchEvent-->ACTION_UP")
                when (showedContentType) {
                    SHOW_SLIDE_CONTENT -> {
                        actionUpShowSlideContent(event)
                    }
                    SHOW_BOTTOM_CONTENT -> {
                        actionUpShowBottomContent(event)
                    }
                    SHOW_TOP_CONTENT -> {
                        actionUpShowTopContent(event)
                    }
                    else -> {}
                }

                topContentLayoutShowed = topLayoutMovedY == measuredHeight
                bottomContentLayoutShowed = totalMovedYDistance == -measuredHeight
            }
            MotionEvent.ACTION_CANCEL -> {
                Log.d(TAG, "onTouchEvent-->ACTION_CANCEL")
                when (showedContentType) {
                    SHOW_SLIDE_CONTENT -> {
                        totalMovedXDistance = lastTotalMovedXDistance
                        scrollTo(-totalMovedXDistance, 0)
                    }
                    SHOW_BOTTOM_CONTENT -> {
                        totalMovedYDistance = lastTotalMovedYDistance
                        //scrollTo(0, -totalMovedYDistance)
                        requestLayout()

                        setViewAlpha(if (totalMovedYDistance == 0) 1F else 0F)
                    }
                    SHOW_TOP_CONTENT -> {
                        topLayoutMovedX = 0
                        topLayoutMovedY = 0
                        requestLayout()
                    }
                    else -> {}
                }
            }
        }
        return true
    }

    override fun performClick(): Boolean {
        return super.performClick()
    }

    override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
        return MarginLayoutParams(context, attrs)
    }

    private fun actionMoveShowSlideContent(event: MotionEvent) {
        val moveX = event.x.toInt()
        val moveY = event.y.toInt()
        val diffValueX = moveX - downX
        val diffValueY = moveY - downY
        if (Math.abs(diffValueX) > Math.abs(diffValueY)) {
            totalMovedXDistance += diffValueX
            calcMovedXDistance += diffValueX
            totalMovedXDistance = if (diffValueX > 0) {
                //右滑
                Math.min(width, totalMovedXDistance)
            } else {
                //左滑
                Math.min(width, Math.max(totalMovedXDistance, 0))
            }
            scrollTo(-totalMovedXDistance, 0)
        }
        downX = moveX
        downY = moveY
    }

    private fun actionMoveShowBottomContent(event: MotionEvent) {
        val moveX = event.x.toInt()
        val moveY = event.y.toInt()
        val diffValueX = moveX - downX
        val diffValueY = moveY - downY
        if (Math.abs(diffValueY) > Math.abs(diffValueX)) {
            totalMovedYDistance += diffValueY
            calcMovedYDistance += diffValueY
            totalMovedYDistance = if (diffValueY > 0) {
                //下滑
                Log.d(TAG, "actionMove--下滑")
                val moveYValue = Math.min(totalMovedYDistance, 0)
                setViewAlpha(if (moveYValue == 0) 1F else Math.abs(calcMovedYDistance.toFloat()) / this.measuredHeight)
                moveYValue
            } else {
                //上滑
                Log.d(TAG, "actionMove--上滑")
                val moveYValue = Math.max(-height, totalMovedYDistance)
                setViewAlpha(0.7F - Math.abs(calcMovedYDistance.toFloat()) / this.measuredHeight)
                moveYValue
            }
            //scrollTo(0, -totalMovedYDistance)
            requestLayout()
        }
        downX = moveX
        downY = moveY
    }

    private fun actionUpShowTopContent(event: MotionEvent) {
        val upX = event.x.toInt()
        val upY = event.y.toInt()
        val diffValueX = upX - downX
        val diffValueY = upY - downY
        if (Math.abs(diffValueX) < Math.abs(diffValueY)) {
            if (currentChildIndex != 0) {
                topLayoutMovedX = 0
            }
            topLayoutMovedY = if (diffValueY > 0) measuredHeight else 0
            requestLayout()
        }
    }

    private fun actionUpShowSlideContent(event: MotionEvent) {
        //左右滑动场景下 只有主页和侧边栏两个页面
        val actionUpDiffValueX = event.x.toInt() - flagDownX
        val modMovedValue = Math.abs(calcMovedXDistance) % width
        if (actionUpDiffValueX > 0) {
            //右滑
            totalMovedXDistance = if (modMovedValue > BaseConstant.MIN_MOVED_DISTANCE) {
                Log.d(TAG, "actionUpShowSlideContent--modMovedValue > BaseConstant.MIN_MOVED_DISTANCE--右滑")
                currentChildIndex--
                currentChildIndex = Math.max(0, currentChildIndex)
                lastTotalMovedXDistance + width
            } else {
                Log.d(TAG, "actionUpShowSlideContent--modMovedValue < BaseConstant.MIN_MOVED_DISTANCE--右滑")
                lastTotalMovedXDistance
            }
            totalMovedXDistance = Math.min(width, totalMovedXDistance)
        } else {
            //左滑
            totalMovedXDistance = if (modMovedValue > BaseConstant.MIN_MOVED_DISTANCE) {
                Log.d(TAG, "actionUpShowSlideContent--modMovedValue > BaseConstant.MIN_MOVED_DISTANCE--左滑")
                currentChildIndex++
                currentChildIndex = Math.min(currentChildIndex, 1)
                lastTotalMovedXDistance - width
            } else {
                Log.d(TAG, "actionUpShowSlideContent--modMovedValue < BaseConstant.MIN_MOVED_DISTANCE--左滑")
                lastTotalMovedXDistance
            }
            totalMovedXDistance = Math.max(totalMovedXDistance, 0)
        }
        scrollTo(-totalMovedXDistance, 0)
        calcMovedXDistance = 0
        lastTotalMovedXDistance = totalMovedXDistance
    }

    private fun actionUpShowBottomContent(event: MotionEvent) {
        val actionUpDiffValueY = event.y.toInt() - flagDownY
        val modMovedValue = Math.abs(calcMovedYDistance) % height
        if (actionUpDiffValueY > 0) {
            //下滑
            totalMovedYDistance = if (modMovedValue > BaseConstant.MIN_MOVED_DISTANCE) {
                Log.d(TAG, "actionUp--(modMovedValue > MIN_MOVED_DISTANCE)--下滑")
                currentChildIndex--
                currentChildIndex = Math.max(currentChildIndex, 1)
                lastTotalMovedYDistance + height
            } else {
                Log.d(TAG, "actionUp--(modMovedValue < MIN_MOVED_DISTANCE)--下滑")
                lastTotalMovedYDistance
            }
            totalMovedYDistance = Math.min(totalMovedYDistance, 0)
        } else {
            //上滑
            totalMovedYDistance = if (modMovedValue > BaseConstant.MIN_MOVED_DISTANCE) {
                Log.d(TAG, "actionUp--(modMovedValue > MIN_MOVED_DISTANCE)--上滑")
                currentChildIndex++
                currentChildIndex = Math.min(currentChildIndex, 2)
                lastTotalMovedYDistance - height
            } else {
                Log.d(TAG, "actionUp--(modMovedValue < MIN_MOVED_DISTANCE)--上滑")
                lastTotalMovedYDistance
            }
            totalMovedYDistance = Math.max(-height, totalMovedYDistance)
        }
        //scrollTo(0, -totalMovedYDistance)
        requestLayout()

        setViewAlpha(if (totalMovedYDistance == 0) 1F else 0F)

        calcMovedYDistance = 0
        lastTotalMovedYDistance = totalMovedYDistance
    }

    private fun setViewAlpha(alphaValue: Float) {
        get(1).alpha = alphaValue
        get(2).alpha = alphaValue
    }

    fun setLauncherContentLayout(launcherLayout: LauncherLayout2?) {
        this.launcherLayout = launcherLayout
    }

    fun setBottomContentLayout(bottomContentLayout: BottomContentLayout?) {
        this.bottomContentLayout = bottomContentLayout
    }

    fun setSlideContentLayout(slideContentLayout: SlideContentLayout?) {
        this.slideContentLayout = slideContentLayout
    }

    fun setTopContentLayout(topContentLayout: TopContentLayout? = null) {
        this.topContentLayout = topContentLayout
    }

    companion object {
        const val TAG = "RootContentLayout"
        const val SHOW_SLIDE_CONTENT = 0x00
        const val SHOW_BOTTOM_CONTENT = 0x01
        const val SHOW_TOP_CONTENT = 0x02
    }
}